﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Input;
using XNAGuiLib.Core.Utilities;

namespace XNAGuiLib.Core.ActionHandling
{
    public class KeyModifier
    {

        /// <summary>
        /// key modifier for no key pressed
        /// </summary>
        public static KeyModifier NONE = new KeyModifier(null);
        /// <summary>
        /// key modifier for left alt key
        /// </summary>
        public static KeyModifier ALT_L = new KeyModifier(new Keys[] { Keys.LeftAlt });
        /// <summary>
        /// key modifier for right alt key
        /// </summary>
        public static KeyModifier ALT_R = new KeyModifier(new Keys[] { Keys.RightAlt });
        /// <summary>
        /// key modifier for left alt and shift key
        /// </summary>
        public static KeyModifier ALTSHIFT_L = new KeyModifier(new Keys[] { Keys.LeftAlt, Keys.LeftShift });
        /// <summary>
        /// key modifier for right alt and shift key
        /// </summary>
        public static KeyModifier ALTSHIFT_R = new KeyModifier(new Keys[] { Keys.RightAlt, Keys.RightShift });
        /// <summary>
        /// key modifier for left control key
        /// </summary>
        public static KeyModifier CRTL_L = new KeyModifier(new Keys[] { Keys.LeftControl});
        /// <summary>
        /// key modifier for right control key
        /// </summary>
        public static KeyModifier CRTL_R = new KeyModifier(new Keys[] { Keys.RightControl });
        /// <summary>
        /// key modifier for left control and alt key
        /// </summary>
        public static KeyModifier CTRLALT_L = new KeyModifier(new Keys[] { Keys.LeftControl, Keys.LeftAlt });
        /// <summary>
        /// key modifier for right control and alt key
        /// </summary>
        public static KeyModifier CTRLALT_R = new KeyModifier(new Keys[] { Keys.RightControl, Keys.RightAlt });
        /// <summary>
        /// key modifier for left control and shift key
        /// </summary>
        public static KeyModifier CTRLSHIFT_L = new KeyModifier(new Keys[] { Keys.LeftControl, Keys.LeftShift });
        /// <summary>
        /// key modifier for right control and shift key
        /// </summary>
        public static KeyModifier CTRLSHIFT_R = new KeyModifier(new Keys[] { Keys.RightControl, Keys.RightShift });
        /// <summary>
        /// key modifier for left control, alt and shift key
        /// </summary>
        public static KeyModifier CTRLALTSHIFT_L = new KeyModifier(new Keys[] { Keys.LeftControl, Keys.LeftAlt, Keys.LeftShift });
        /// <summary>
        /// key modifier for right control, alt and shift key
        /// </summary>
        public static KeyModifier CTRLALTSHIFT_R = new KeyModifier(new Keys[] { Keys.RightControl, Keys.RightAlt, Keys.RightShift });
        /// <summary>
        /// key modifier for left shift key
        /// </summary>
        public static KeyModifier SHIFT_L = new KeyModifier(new Keys[] { Keys.LeftShift });
        /// <summary>
        /// key modifier for right shift key
        /// </summary>
        public static KeyModifier SHIFT_R = new KeyModifier(new Keys[] { Keys.RightShift });
        /// <summary>
        /// key modifier for left windows key
        /// </summary>
        public static KeyModifier WIN_L = new KeyModifier(new Keys[] { Keys.LeftWindows });
        /// <summary>
        /// key modifier for right windows key
        /// </summary>
        public static KeyModifier WIN_R = new KeyModifier(new Keys[] { Keys.RightWindows });


        #region Private Field - _keys
        /// <summary>
        /// private field for keys to check for this key modifier
        /// </summary>
        Keys[] _keys;
        #endregion

        private Enums.KeyboardKeyPositions _keyPosition;


        #region Constructor - KeyModifier(Keys[] keys)
        /// <summary>
        /// default private constructor
        /// </summary>
        /// <param name="keys">array of keys</param>
        private KeyModifier(Keys[] keys)
        {
            this._keys = keys;
            this._keyPosition = Enums.KeyboardKeyPositions.Down;
        }
        #endregion


        #region Constructor - KeyModifier(Keys[] keys)
        /// <summary>
        /// private constructor with key position value
        /// </summary>
        /// <param name="keys">array of keys</param>
        /// <param name="keyPosition">position the keys of this modifier should be checked for</param>
        private KeyModifier(Keys[] keys, Enums.KeyboardKeyPositions keyPosition)
        {
            this._keys = keys;
            this._keyPosition = keyPosition;
        }
        #endregion


        #region KeyModifier Public Method - CheckKeyModifier(KeyboardState ks)
        /// <summary>
        /// check the KeyModifier's key-array if all keys are down or not
        /// </summary>
        /// <param name="ks">keyboardstate on which the keymodifier will check</param>
        /// <returns>true if all keys are down, false otherwise</returns>
        public bool CheckKeyModifier(KeyboardState ks, KeyboardState oks)
        {
            // check if key modifier is set to 'none'
            if (_keys != null)
            {
                bool modified = false;

                switch (_keyPosition)
                {
                    case Enums.KeyboardKeyPositions.Down:
                        foreach (Keys key in _keys)
                        {
                            if (ks.IsKeyDown(key))
                                modified = true;
                            else return false;
                        }
                        break;

                    case Enums.KeyboardKeyPositions.Up:
                        foreach (Keys key in _keys)
                        {
                            if (ks.IsKeyUp(key))
                                modified = true;
                            else return false;
                        }
                        break;

                    case Enums.KeyboardKeyPositions.Pressed:
                        foreach (Keys key in _keys)
                        {
                            if (ks.IsKeyUp(key) && oks.IsKeyDown(key))
                                modified = true;
                            else return false;
                        }
                        break;
                }
                
                return modified;
            }
            return true;
        }
        #endregion


        #region KeyModifier Public Static Method - Generate(Keys[] keys)
        /// <summary>
        /// generates a new key modifier for custom keys
        /// </summary>
        /// <param name="keys">the keys checked by the key modifier</param>
        /// <returns>new KeyModifier object</returns>
        public static KeyModifier Generate(Keys[] keys)
        {
            return new KeyModifier(keys);
        }
        #endregion

        #region KeyModifier Public Static Method - Generate(List<Keys> keys)
        /// <summary>
        /// generates a new key modifier for custom keys
        /// </summary>
        /// <param name="keys">the keys checked by the key modifier</param>
        /// <returns>new KeyModifier object</returns>
        public static KeyModifier Generate(List<Keys> keys)
        {
            return new KeyModifier(keys.ToArray());
        }
        #endregion

        #region KeyModifier Public Static Method - Generate(string key)
        /// <summary>
        /// generates a new key modifier for custom keys
        /// </summary>
        /// <param name="key">the key as string checked by the key modifier</param>
        /// <returns>new KeyModifier object</returns>
        public static KeyModifier Generate(string key)
        {
            return KeyModifier.Generate(new Keys[] { KeyMap.Key(key) });
        }
        #endregion


        #region KeyModifier Public Static Method - Generate(Keys[] keys, Enums.KeyboardKeyPositions keyPosition)
        /// <summary>
        /// generates a new key modifier for custom keys
        /// </summary>
        /// <param name="keys">the keys checked by the key modifier</param>
        /// <param name="keyPosition">the position the key is checked for</param>
        /// <returns>new KeyModifier object</returns>
        public static KeyModifier Generate(Keys[] keys, Enums.KeyboardKeyPositions keyPosition)
        {
            return new KeyModifier(keys, keyPosition);
        }
        #endregion

        #region KeyModifier Public Static Method - Generate(List<Keys> keys, Enums.KeyboardKeyPositions keyPosition)
        /// <summary>
        /// generates a new key modifier for custom keys
        /// </summary>
        /// <param name="keys">the keys checked by the key modifier</param>
        /// <param name="keyPosition">the position the key is checked for</param>
        /// <returns>new KeyModifier object</returns>
        public static KeyModifier Generate(List<Keys> keys, Enums.KeyboardKeyPositions keyPosition)
        {
            return new KeyModifier(keys.ToArray(), keyPosition);
        }
        #endregion

        #region KeyModifier Public Static Method - Generate(string key, Enums.KeyboardKeyPositions keyPosition)
        /// <summary>
        /// generates a new key modifier for custom keys
        /// </summary>
        /// <param name="key">the key as string checked by the key modifier</param>
        /// <param name="keyPosition">the position the key is checked for</param>
        /// <returns>new KeyModifier object</returns>
        public static KeyModifier Generate(string key, Enums.KeyboardKeyPositions keyPosition)
        {
            return KeyModifier.Generate(new Keys[] { KeyMap.Key(key) }, keyPosition);
        }
        #endregion
    }
}
